#include"server_backend.h"
#include "network.h"
#include "filesys.h"
#include "cmd_code.h"
#include<stdio.h>
#include<unistd.h>
#include<string.h>
#include<dirent.h>
#include<fcntl.h>
#include<sys/types.h>
#include<sys/stat.h>
#include<libgen.h>

char serv_cur_dir[DIR_MAX_SIZE] = SERV_ROOT_DIR;
int dir_depth = 0;

//监听客户端指令
int getClntCode(int clntfd){
    int cmd_code = 0;
    int read_len = 0;
    printf("waiting incoming command...\n");
    if((read_len = read(clntfd,&cmd_code,sizeof(int)))< 0)
        return CMD_ERR;
    printf("getClntCode(): read_len:%d cmd_code:%d\n",read_len,cmd_code);
    return cmd_code;
}

//匹配客户端指令
void serverResponse(int clntfd, int cmd_code){
    int success = CMD_SUCCESS, fail = CMD_ERR;
    if(cmd_code == CMD_ERR){
        write(clntfd,&fail,sizeof(int));
        return;
    }
    write(clntfd,&success,sizeof(int));
    switch (cmd_code)
    {
        case CMD_ECHO:
            responseEcho(clntfd);  
            break;
        case CMD_LS:
            responseLs(clntfd);
            break;
        case CMD_CD:
            responseCd(clntfd);
            break;
        case CMD_PUT:
            responsePut(clntfd);
            break;
        case CMD_GET:
            responseGet(clntfd);
            break;
        default:
            write(clntfd,&fail,sizeof(int));
            break;
    }
}

void responseEcho(int clntfd){
    int str_len = 0;
    char buf[BUFFER_SIZE];
    while((str_len = read(clntfd,buf,BUFFER_SIZE)) > 0){
        if(str_len == 1 && buf[0] == 'q')
            break;
        int write_len = write(clntfd,buf,str_len);
        printf("读出:%d 写入：%d\n",str_len,write_len);
    }
    printf("successful quit echo\n");
    return;
}

void responseLs(int clntfd){
    char dir_info[DIR_MAX_SIZE];
    char ls_info[LS_INFO_SZ];
    memset(dir_info,0,DIR_MAX_SIZE);
    memset(ls_info,0,LS_INFO_SZ);
    

    printf("responseLs():\n");
    printf("读取:%s\n",serv_cur_dir);
    fsLs(serv_cur_dir,ls_info);

    //组装所有信息到write_buf上输出
    char write_buf[BUFFER_SIZE]; 
    memset(write_buf,0,BUFFER_SIZE);

    strcat(dir_info,"当前目录为:");
    strcat(dir_info,serv_cur_dir);
    strcat(dir_info,"\n");
    strcat(write_buf,dir_info);
    strcat(write_buf,ls_info);
    strcat(write_buf,"\000");

    int datalen = strlen(write_buf);
    write(clntfd,&datalen,sizeof(int));
    int write_len = write(clntfd,write_buf,datalen);
    printf("信息长度:%d, 写出:%d\n",datalen, write_len);
    printf("successful quit ls\n");
}

int responseCd(int clntfd){
    char temp_dir[DIR_MAX_SIZE];
    memset(temp_dir,0,DIR_MAX_SIZE);
    read(clntfd,temp_dir,DIR_MAX_SIZE);
    int status = FSTAT_NOMAL;
    if(!strcmp(temp_dir,".") || !strcmp(temp_dir,"./")){
        status = FSTAT_DIR_NOCHANGE;
    }
    else if(!strcmp(temp_dir,"..") || !strcmp(temp_dir,"../")){
        if(dir_depth == 0){
            printf("已到达根地址\n");
            status = FSTAT_IS_ROOTDIR;
        }
        else{
            dir_depth--;
            int i = strlen(serv_cur_dir) - 1;
            printf("curDir长度：%d\n",i);
            for(; i >= 0; i--){
                if(serv_cur_dir[i] == '/')
                    break;
            }
            for(int j = 0; j < i; j++){
                temp_dir[j] = serv_cur_dir[j]; 
            }

            strcpy(serv_cur_dir,temp_dir);
            printf("地址变为:%s 目前深度:%d \n",serv_cur_dir,dir_depth);
            status =  FSTAT_DIR_CHANGED;
        }
    }
    else{
        char *new_dir = mergePath(serv_cur_dir,temp_dir);  
        printf("实际查找目录:%s\n",new_dir);
        DIR *dp = opendir(new_dir);
        if(dp != NULL){
            strcpy(serv_cur_dir,new_dir);
            int newDepth = -1;
            for(int i = 0; i < strlen(serv_cur_dir); i++){
                if(serv_cur_dir[i] == '/')
                    newDepth++;
            }
            dir_depth = newDepth;
            printf("地址变为:%s 目前深度:%d\n",serv_cur_dir,dir_depth);
            status = FSTAT_DIR_CHANGED;
        }
        else{
            status = FSTAT_NO_SUCH_FILE;
        }     
    }

    int dir_len = strlen(serv_cur_dir);
    write(clntfd,&status,sizeof(int));
    write(clntfd,&dir_len,sizeof(int));
    write(clntfd,&serv_cur_dir,dir_len);

    printf("succesful exit cd\n");
    return status;
}

int responsePut(int clntfd){
    return recvFile(clntfd,serv_cur_dir);
}

int responseGet(int clntfd){
    //服务器收到客户端路径 
    int path_len = 0; 
    char file_path[DIR_MAX_SIZE];
    memset(file_path,0,DIR_MAX_SIZE);

    read(clntfd,&path_len,sizeof(int));
    read(clntfd, &file_path, path_len);

    char *dst_path = mergePath(serv_cur_dir,file_path);
    printf("获取路径:%s\n",file_path);
    printf("实际要下载的文件路径:%s\n",dst_path);
    
    //查找对应文件, 若找到通知客户端下载, 否则停止下载
    int status = 0;
    int filefd = open(dst_path, O_RDONLY, 777);
    struct stat statbuf;
    fstat(filefd, &statbuf);
    printf("filefd = %d\n",filefd);

    if(filefd == -1){
        perror("errno");
        status = FSTAT_NO_SUCH_FILE;
        write(clntfd,&status,sizeof(int));
        return -1;
    }
    else if(S_ISDIR(statbuf.st_mode)){
        status = FSTAT_DIR;
        printf("错误:%s是一个目录\n",dst_path);
        write(clntfd,&status,sizeof(int));
        close(filefd);
        return -1;
    }
    else{
        perror("errno:");
        status = FSTAT_NOMAL;
        write(clntfd,&status,sizeof(int));

    }

    //等待客户端打开接受流
    printf("等待客户端打开接收流\n");
    read(clntfd, &status, sizeof(int));
    if(status == FSTAT_OPEN_ERROR){
        printf("客户端发生异常\n");
        close(filefd);
        return -1;
    }

    //成功则开始上传
    int fdata_len = statbuf.st_size;
    printf("开始上传:%s 长度:%d\n",dst_path,fdata_len);

    //发送文件长
    write(clntfd,&fdata_len, sizeof(int));

    int send_cur = 0; char bit;
    while(send_cur < fdata_len){
        read(filefd,&bit,1);
        int send_cnt = write(clntfd,&bit,1);
        int res = read(clntfd,&status,sizeof(int));
        if(res < 0 || status == FSTAT_GET_ERROR){
            printf("上传过程中出现错误\n");
            close(filefd);
            return -1;
        }

        send_cur += send_cnt;
        printf("写入:%d 目前:%d\n",send_cur,send_cnt);
    }
    
    printf("文件传输完毕\n");

   
    close(filefd);
    return 0;
}

























